package bu.utils;

import android.content.Context;
import android.content.SharedPreferences;


import java.lang.reflect.Method;
import java.util.Map;

/**
 * Author      : BWj
 * Date        : 2018/12/27
 * Description : SharedPreferences工具类
 */
/*
 * 不传Context参数的，使用ApplicationContext，必须初始化
 * 不传fileName参数的，使用默认文件名
 */
public class SPUtil {
    /* 默认的文件名 */
    private static String DEFAULT_FILE_NAME = "default_share_data";
    private static Context appContext;

    /**
     * 初始化 ApplicationContext
     *
     * @param context
     */
    public static void init(Context context) {
        appContext = context.getApplicationContext();
    }

    /**
     * 获取ApplicationContext
     *
     * @return
     */
    private static Context getAppContext() {
        if (appContext == null) {
            throw new RuntimeException("SPUtil没有初始化,必须传入Context");
        } else {
            return appContext;
        }
    }


    /**
     * 获取 SharedPreferences 对象
     *
     * @param context  上下文
     * @param fileName 文件名称
     * @return
     */
    private static SharedPreferences getSP(Context context, String fileName) {
        return context.getSharedPreferences(fileName, Context.MODE_PRIVATE);
    }

    /**
     * 存
     * 是-默认文件
     * 是-ApplicationContext
     *
     * @param key   键
     * @param value 值
     * @param <E>   泛型，自动根据值进行处理
     */
    public static <E> void put(String key, E value) {
        put(DEFAULT_FILE_NAME, key, value);
    }

    /**
     * 存
     * 否-默认文件
     * 是-ApplicationContext
     *
     * @param fileName 文件名称
     * @param key      键
     * @param value    值
     * @param <E>      泛型，自动根据值进行处理
     */
    public static <E> void put(String fileName, String key, E value) {
        put(getAppContext(), fileName, key, value);
    }

    /**
     * 存
     * 是-默认文件
     * 否-ApplicationContext
     *
     * @param context 上下文
     * @param key     键
     * @param value   值
     * @param <E>     泛型，自动根据值进行处理
     */
    public static <E> void put(Context context, String key, E value) {
        put(context, DEFAULT_FILE_NAME, key, value);
    }

    /**
     * 存
     * 否-默认文件
     * 否-ApplicationContext
     *
     * @param context  上下文
     * @param fileName 文件名
     * @param key      键
     * @param value    值
     * @param <E>      泛型，自动根据值进行处理
     */
    public static <E> void put(Context context, String fileName, String key, E value) {
        SharedPreferences.Editor editor = getSP(context, fileName).edit();
        if (value instanceof String || value instanceof Integer || value instanceof Boolean ||
                value instanceof Float || value instanceof Long || value instanceof Double) {
            editor.putString(key, String.valueOf(value));
            SPCompat.apply(editor);
        }
    }

    /**
     * 取-根据默认值的类型返回结果
     * 是-默认文件
     * 是-ApplicationContext
     *
     * @param key          键
     * @param defaultValue 值
     * @param <E>          泛型，自动根据值进行处理
     * @return
     */
    public static <E> E get(String key, E defaultValue) {
        return get(DEFAULT_FILE_NAME, key, defaultValue);
    }

    /**
     * 取-根据默认值的类型返回结果
     * 否-默认文件
     * 是-ApplicationContext
     *
     * @param fileName     文件名
     * @param key          键
     * @param defaultValue 值
     * @param <E>          泛型，自动根据值进行处理
     * @return
     */
    public static <E> E get(String fileName, String key, E defaultValue) {
        return get(getAppContext(), fileName, key, defaultValue);
    }

    /**
     * 取-根据默认值的类型返回结果
     * 是-默认文件
     * 否-ApplicationContext
     *
     * @param context      上下文
     * @param key          键
     * @param defaultValue 值
     * @param <E>          泛型，自动根据值进行处理
     * @return
     */
    public static <E> E get(Context context, String key, E defaultValue) {
        return get(context, DEFAULT_FILE_NAME, key, defaultValue);
    }


    /**
     * 取-根据默认值的类型返回结果
     * 否-默认文件
     * 否-ApplicationContext
     *
     * @param context      上下文
     * @param fileName     文件名
     * @param key          键
     * @param defaultValue 值
     * @param <E>          泛型，自动根据值进行处理
     * @return String, Integer, Boolean，Float，Long，Double之外的类型返回null
     */
    public static <E> E get(Context context, String fileName, String key, E defaultValue) {
        String value = getSP(context, fileName).getString(key, String.valueOf(defaultValue));
        if (defaultValue instanceof String) {
            return (E) value;
        }
        if (defaultValue instanceof Integer) {
            return (E) Integer.valueOf(value);
        }
        if (defaultValue instanceof Integer) {
            return (E) Boolean.valueOf(value);
        }
        if (defaultValue instanceof Integer) {
            return (E) Float.valueOf(value);
        }
        if (defaultValue instanceof Long) {
            return (E) Long.valueOf(value);
        }
        if (defaultValue instanceof Double) {
            return (E) Double.valueOf(value);
        }
        return null;
    }

    /**
     * 移除某个key值已经对应的值
     * 是-默认文件
     * 是-ApplicationContext
     *
     * @param key 键
     */
    public static void remove(String key) {
        remove(DEFAULT_FILE_NAME, key);
    }

    /**
     * 移除某个key值已经对应的值
     * 否-默认文件
     * 是-ApplicationContext
     *
     * @param fileName 文件名
     * @param key      键
     */
    public static void remove(String fileName, String key) {
        remove(getAppContext(), fileName, key);
    }

    /**
     * 移除某个key值已经对应的值
     * 是-默认文件
     * 否-ApplicationContext
     *
     * @param context 上下文
     * @param key     键
     */
    public static void remove(Context context, String key) {
        remove(context, DEFAULT_FILE_NAME, key);
    }


    /**
     * 移除某个key值已经对应的值
     * 否-默认文件
     * 否-ApplicationContext
     *
     * @param context  上下文
     * @param fileName 文件名
     * @param key      键
     */
    public static void remove(Context context, String fileName, String key) {
        SharedPreferences.Editor editor = getSP(context, fileName).edit();
        editor.remove(key);
        SPCompat.apply(editor);
    }

    /**
     * 清除所有数据
     * 是-默认文件
     * 是-ApplicationContext
     */
    public static void clear() {
        clear(getAppContext(), DEFAULT_FILE_NAME);
    }

    /**
     * 清除所有数据
     * 否-默认文件
     * 是-ApplicationContext
     *
     * @param fileName 文件名
     */
    public static void clear(String fileName) {
        clear(getAppContext(), fileName);
    }

    /**
     * 清除所有数据
     * 是-默认文件
     * 否-ApplicationContext
     *
     * @param context 上下文
     */
    public static void clear(Context context) {
        clear(context, DEFAULT_FILE_NAME);
    }

    /**
     * 清除所有数据
     * 否-默认文件
     * 否-ApplicationContext
     *
     * @param context  上下文
     * @param fileName 文件名
     */
    public static void clear(Context context, String fileName) {
        SharedPreferences.Editor editor = getSP(context, fileName).edit();
        editor.clear();
        SPCompat.apply(editor);
    }

    /**
     * 查询某个key是否已经存在
     * 是-默认文件
     * 是-ApplicationContext
     *
     * @param key 键
     * @return 有返回true，没有返回false
     */
    public static boolean contains(String key) {
        return contains(DEFAULT_FILE_NAME, key);
    }

    /**
     * 查询某个key是否已经存在
     * 否-默认文件
     * 是-ApplicationContext
     *
     * @param fileName 文件名
     * @param key      键
     * @return 有返回true，没有返回false
     */
    public static boolean contains(String fileName, String key) {
        return contains(getAppContext(), fileName, key);
    }

    /**
     * 查询某个key是否已经存在
     * 是-默认文件
     * 否-ApplicationContext
     *
     * @param context 上下文
     * @param key     键
     * @return 有返回true，没有返回false
     */
    public static boolean contains(Context context, String key) {
        return contains(context, DEFAULT_FILE_NAME, key);
    }

    /**
     * 查询某个key是否已经存在
     * 否-默认文件
     * 否-ApplicationContext
     *
     * @param context  上下文
     * @param fileName 文件名
     * @param key      键
     * @return 有返回true，没有返回false
     */
    public static boolean contains(Context context, String fileName, String key) {
        return getSP(context, fileName).contains(key);
    }

    /**
     * 返回所有的键值对
     * 是-默认文件
     * 是-ApplicationContext
     *
     * @return
     */
    public static Map<String, ?> getAll() {
        return getAll(DEFAULT_FILE_NAME);
    }

    /**
     * 返回所有的键值对
     * 否-默认文件
     * 是-ApplicationContext
     *
     * @return
     */
    public static Map<String, ?> getAll(String fileName) {
        return getAll(getAppContext(), fileName);
    }

    /**
     * 返回所有的键值对
     * 否-默认文件
     * 否-ApplicationContext
     *
     * @param context 上下文
     * @return
     */
    public static Map<String, ?> getAll(Context context) {
        return getAll(context, DEFAULT_FILE_NAME);
    }

    /**
     * 返回所有的键值对
     * 否-默认文件
     * 否-ApplicationContext
     *
     * @param context  上下文
     * @param fileName 文件名
     * @return
     */
    public static Map<String, ?> getAll(Context context, String fileName) {
        return getSP(context, fileName).getAll();
    }


    /**
     * 创建一个解决SharedPreferencesCompat.apply方法的一个兼容类
     */
    private static class SPCompat {
        private static final Method S_APPLY_METHOD = findApplyMethod();

        /**
         * 反射查找apply的方法
         *
         * @return
         */
        @SuppressWarnings({"unchecked", "rawtypes"})
        private static Method findApplyMethod() {
            try {
                Class clz = SharedPreferences.Editor.class;
                return clz.getMethod("apply");
            } catch (NoSuchMethodException e) {
            }
            return null;
        }

        /**
         * 如果找到则使用apply执行，否则使用commit
         *
         * @param editor
         */
        public static void apply(SharedPreferences.Editor editor) {
            try {
                if (S_APPLY_METHOD != null) {
                    S_APPLY_METHOD.invoke(editor);
                    return;
                }
            } catch (Exception e) {
            }
            editor.commit();
        }
    }
}
